﻿using System;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceProcess;
using System.Threading;
using NLog;

namespace LiquesceFTPSvc
{
   public partial class LiquesceFTPSvc : ServiceBase
   {
      static private readonly Logger Log = LogManager.GetCurrentClassLogger();

      public LiquesceFTPSvc()
      {
         try
         {
            AppDomain.CurrentDomain.UnhandledException += LogUnhandledException;
         }
         catch (Exception ex)
         {
            try
            {
               Log.FatalException("Failed to attach unhandled exception handler...", ex);
            }
            catch
            {
            }
         }
         Log.Info("LiquesceFTPSvc object.");
         InitializeComponent();
      }

      public bool RunningAsService { get; set; }

      private static void LogUnhandledException(object sender, UnhandledExceptionEventArgs e)
      {
         try
         {
            Log.Fatal("Unhandled exception.\r\n{0}", e.ExceptionObject);
            Exception ex = e.ExceptionObject as Exception;
            if (ex != null)
            {
               Log.FatalException("Exception details", ex);
            }
            else
            {
               Log.Fatal("Unexpected exception.");
            }
         }
         catch
         {
         }
      }

      private static ServiceHost _ILiquesceFTPHost;
      private static ServiceHost _ILiquesceFTPHostCallBack;

      public void StartService(string[] args)
      {
         OnStart(args);
      }

      public void StopService()
      {
         OnStop();
      }

      protected override void OnStart(string[] args)
      {
         Log.Info("OnStart");
         try
         {
            if (RunningAsService)
               RequestAdditionalTime(30000);
            // let the SCM know that this part could take a while due to other services starting up
            foreach (string arg in args)
            {
               Log.Debug(arg);
               switch (arg.ToUpper())
               {
                  case "-DEBUG":
                     Log.Info("Launching debugger.");
                     Debugger.Launch();
                     break;
               }
            }
            _ILiquesceFTPHost = new ServiceHost(typeof(LiquesceFTPFacade));
            _ILiquesceFTPHostCallBack = new ServiceHost(typeof(LiquesceFTPCallBackFacade));
            _ILiquesceFTPHost.Open();
            _ILiquesceFTPHostCallBack.Open();

            if (RunningAsService)
            {
               RequestAdditionalTime(30000);
               // let the SCM know that this part could take a while due to other services starting up
               base.OnStart(args);

               Log.Info("Create Management object to hold the listeners etc.");
               RequestAdditionalTime(30000);
               // let the SCM know that this part could take a while due to other services starting up
            }
            // Queue the main work as a thread pool task as we want this method to finish promptly.
            ThreadPool.QueueUserWorkItem(ThreadProc, this);
         }
         catch (Exception ex)
         {
            /*
Windows Server 2003/Windows XP - use the HttpCfg.exe tool
Windows 7/Windows Server 2008 - configure these settings with the Netsh.exe tool (you need to deal with UAC here). The steps are mentioned below:
1. Go to Start > Accessories > Command Prompt > Right-Click (Run as Administrator)
2. Execute this at the command prompt:
HTTP could not register URL http://+:8831/Design_Time_Addresses/LiquesceFTPSvc/LiquesceFTPCallBackFacade/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details).
    netsh http add urlacl url=http://+:8831/Design_Time_Addresses/LiquesceFTPSvc/LiquesceFTPCallBackFacade user=DOMAIN\username
    8000 here is your port number, you can replace this with a port number of  your choice (using which your WCF service is hosted)            
             */
            Log.ErrorException("LiquesceFTPSvc startup error.", ex);
            base.EventLog.WriteEntry(ex.Message, EventLogEntryType.Error);
            OnStop();
            if (RunningAsService)
               Stop();
            throw;
         }
      }

      /// <summary>
      /// This thread routine performs the task of initializing the ManagementLayer.
      /// </summary>
      /// <param name="stateInfo">Object passed into the method for context info.</param>
      static void ThreadProc(Object stateInfo)
      {
         Log.Info("LiquesceFTPSvc object starting.");
         LiquesceFTPSvc me = stateInfo as LiquesceFTPSvc;
         try
         {
            Log.Info("Running Assembly Information.");

            ManagementLayer.Instance.Start(null);
            Log.Info("Blocking thread ManagementLayer.Instance.Start has exited.");
         }
         catch (Exception ex)
         {
            Log.ErrorException("LiquesceFTPSvc startup error.", ex);
            if (me != null)
            {
               me.OnStop();
               if (me.RunningAsService)
                  ((ServiceBase)me)/*.base*/.Stop();
            }
            throw;
         }
      }

      /// <summary>
      /// "Play nice" with exceptions so that the service can exit when asked (Forced)
      /// </summary>
      protected override void OnStop()
      {
         try
         {
            Log.Info("Stop the ManagementLayer and remove");
            if (RunningAsService)
               RequestAdditionalTime(30000);


            // Then stop the host calling in
            if (_ILiquesceFTPHost != null)
               _ILiquesceFTPHost.Close();
            // Now stop the drives
            ManagementLayer.Instance.Stop();

            // Now stop the callbacks that would be firing out stating the stop has just occurred
            if (_ILiquesceFTPHostCallBack != null)
               _ILiquesceFTPHostCallBack.Close();

            Log.Info("LiquesceFTPSvc stopped.");
         }
         catch (Exception ex)
         {
            Log.ErrorException("LiquesceFTPSvc Shutdown error.", ex);
         }
         finally
         {
            Log.Info("base.OnStop()");
            if (RunningAsService)
               base.OnStop();
         }
      }
   }
}
